package exquery

import setupx.entity.ClassSpecies
import exquery.valuebeans.export.SpeciesVO
import taxonomy.TaxonomyNames
import setupx.entity.ExperimentClass
import setupx.entity.ClassSample
import exquery.util.CommonUtil

import setupx.entity.ClassOrgan
import org.apache.log4j.Logger
import exquery.common.SpeciesUtil
import taxonomy.NCBITaxonomyService
import exquery.valuebeans.export.TaxonomyDivisionVO
import taxonomy.TaxonomyDivisions
import taxonomy.TaxonomyNodes

class SpeciesService {

    static transactional = true
    Logger gLogger = Logger.getLogger(SpeciesService.class)

    def taxonomyService = new NCBITaxonomyService()

    /**
     * to get the distinct list of species 
     * @return
     */
    Collection<SpeciesVO> getUniqueSxSpecies() {
        Collection<SpeciesVO> SXspeciesVOList = null
        def uniqueList = ClassSpecies.executeQuery("Select distinct cs.species_name from setupx.entity.ClassSpecies cs")
        SpeciesVO speciesVO = null
        if(uniqueList!=null && uniqueList.size()>0){
           SXspeciesVOList = new ArrayList<SpeciesVO>()
           uniqueList.each {species->
               gLogger.info "************Process Species ::: ${species}*******************"
               speciesVO = getSXSpeciesBySpeciesName(species)
               //gLogger.info "ExperiemntCount :: ${speciesVO.getExperimentCount()}"
               SXspeciesVOList.add(speciesVO)
           }
        }
        return SXspeciesVOList
    }

    /**
     * to get the distinct NCBI Ids of species 
     * @return
     */
    def getUniqueSxSpeciesNCBIIds(){
        def taxIds

        def uniqueList = ClassSpecies.executeQuery("Select distinct cs.species_name from setupx.entity.ClassSpecies cs")

        if(uniqueList!=null && uniqueList.size()>0){
            taxIds = TaxonomyNames.executeQuery("select distinct tn.tax.id from taxonomy.TaxonomyNames tn  where upper(tn.nameTxt) in (:uniqueList) ",["uniqueList": CommonUtil.getInstance().toUpper(uniqueList)])
        }

        gLogger.info "SetupX taxIds :: ${taxIds}"
        return taxIds
    }

    /**
     * get species by species name
     * @param speciesName
     * @return
     */
    SpeciesVO getSXSpeciesBySpeciesName(String speciesName){
       //gLogger.info "speciesName:: ${speciesName}"
       SpeciesVO speciesVO = SpeciesUtil.getInstance().getSXSpeciesBySpeciesName(speciesName)
       //println "speciesVO:: ${speciesVO}"
       return speciesVO
    }

    /**
     * to get species by ncbiID
     * @param ncbiID
     * @return
     */
    SpeciesVO getSXSpeciesByNCBISpeciesId(Long ncbiID){
        def taxonomyNames = taxonomyService.getTaxonomyScientificName(ncbiID)
        SpeciesVO speciesVO = getSXSpeciesBySpeciesName(taxonomyNames)
        return speciesVO
    }

    /**
     * get the list of class Ids for the species name 
     * @param speciesName
     * @return
     */
    def getClassIdsBySpeciesName(String speciesName){
        def idList
        def taxonomyNames = taxonomyService.getAllNamesByTaxonomyName(speciesName)
        //println "taxonomyNames:: ${taxonomyNames}"
        //println "taxonomyNames.toUpper:: ${CommonUtil.getInstance().toUpper(taxonomyNames)}"

        if(taxonomyNames!=null){
            if( taxonomyNames instanceof Collection ){
                if( taxonomyNames?.size()!=0 ){
                    idList = ClassSpecies.executeQuery("Select distinct cs.experimentclass.id from setupx.entity.ClassSpecies cs where upper(cs.species_name) in (:taxonomyNames) ",["taxonomyNames":CommonUtil.getInstance().toUpper(taxonomyNames)])
                }
            }else if( taxonomyNames instanceof Long ){
                idList = ClassSpecies.executeQuery("Select distinct cs.experimentclass.id from setupx.entity.ClassSpecies cs where upper(cs.species_name) = :taxonomyNames ",["taxonomyNames":taxonomyNames.toString().toUpperCase()])
            }
            gLogger.info "ClassIds Count :: ${idList?.size()}"

        }else{
          idList = ClassSpecies.executeQuery("Select distinct cs.experimentclass.id from setupx.entity.ClassSpecies cs where upper(cs.species_name) = :speciesName ",["speciesName":speciesName.toString().toUpperCase()])
        }
        return idList
    }

    /**
     * to get all species by taxonomy names 
     * @param taxonomyNames
     * @return
     */
    Collection<ClassSpecies> getAllSxSpeciesByTexonomyNames(def taxonomyNames){
       Collection< ClassSpecies> resultCollection  = null;
       if(taxonomyNames!=null){
            if( taxonomyNames instanceof Collection ){
                if( taxonomyNames?.size()!=0 ){
                    resultCollection = ClassSpecies.executeQuery("Select cs from setupx.entity.ClassSpecies cs where upper(cs.species_name) in (:taxonomyNames) order by cs.id", ["taxonomyNames":CommonUtil.getInstance().toUpper(taxonomyNames)])
                }
            }else if( taxonomyNames instanceof Collection ){
                resultCollection = ClassSpecies.executeQuery("Select cs from setupx.entity.ClassSpecies cs where upper(cs.species_name) = :taxonomyNames order by cs.id", ["taxonomyNames":taxonomyNames.toString().toUpperCase()])
            }


       }
       return resultCollection
    }

    /**
     * to get the list of experiment Ids for the species name
     * @param speciesName
     * @return
     */
    def getExperimentIdsBySpeciesName(String speciesName){

        def classIds = getClassIdsBySpeciesName(speciesName)

        def idList
        if(classIds!=null){
          if( classIds instanceof Collection ){
              if( classIds?.size()!=0 ){
                idList = ExperimentClass.executeQuery("Select distinct ec.experiment.id from setupx.entity.ExperimentClass ec where ec.id in (:classIds) ",["classIds":classIds])
              }
          }else if( classIds instanceof Long ){
            idList = ExperimentClass.executeQuery("Select distinct ec.experiment.id from setupx.entity.ExperimentClass ec where ec.id = :classIds ",["classIds":classIds])
          }

        }
        gLogger.info "Experiments Count :: ${idList?.size()}"

        return idList
    }

    /**
     * to get the list of sample Ids for the species name
     * @param speciesName
     * @return
     */
    def getSampleIdsBySpeciesName(String speciesName){
        def classIds = getClassIdsBySpeciesName(speciesName)
        def idList
        if(classIds!=null){
            if( classIds instanceof Collection ){
                if( classIds?.size()!=0 ){
                    idList = ClassSample.executeQuery("Select distinct cs.id from setupx.entity.ClassSample cs where cs.experimentclass.id in (:classIds) and cs.label != null and cs.label!='' ",["classIds":classIds])
                }
            }else if( classIds instanceof Long ){
                idList = ClassSample.executeQuery("Select distinct cs.id from setupx.entity.ClassSample cs where cs.experimentclass.id = :classIds and cs.label != null and cs.label!='' ",["classIds":classIds])
            }

        }
        gLogger.info "SampleIds Count :: ${idList?.size()}"

        return idList
    }

    /**
     * to get distinct list of Organs for the species name 
     * @param speciesName
     * @return
     */
    def getOrgansBySpeciesName(String speciesName){
        def classIds = getClassIdsBySpeciesName(speciesName)
        def organsList
        if(classIds!=null){
            if( classIds instanceof Collection ){
                if( classIds?.size()!=0 ){
                    organsList = ClassOrgan.executeQuery("Select distinct co.organ_name from setupx.entity.ClassOrgan co where co.experimentclass.id in (:classIds) ",["classIds":classIds])
                }
            }else if( classIds instanceof Long ){
                organsList = ClassOrgan.executeQuery("Select distinct co.organ_name from setupx.entity.ClassOrgan co where co.experimentclass.id = :classIds ",["classIds":classIds])
            }
        }
        if(organsList!=null && organsList.size()>0){
          organsList = CommonUtil.getInstance().getDistinctList(organsList)
        }
        gLogger.info "Organs Count :: ${organsList?.size()}"
        return organsList

    }

    /**
     * to get species name by classIds
     * @param classIds
     * @return
     */
    def getSpeciesByClassIds(def classIds){
        def speciesList

        if(classIds!=null){
            def tempSpeciesList
            if( classIds instanceof Collection ){
                if( classIds?.size()!=0 ){
                    tempSpeciesList = ClassSpecies.executeQuery("Select distinct cs.species_name from setupx.entity.ClassSpecies cs where (cs.experimentclass.id) in (:classIds) ",["classIds":classIds])
                }
            }else if( classIds instanceof Long ){
                tempSpeciesList = ClassSpecies.executeQuery("Select distinct cs.species_name from setupx.entity.ClassSpecies cs where (cs.experimentclass.id) = :classIds ",["classIds":classIds])
            }

            def idList = []
            if(tempSpeciesList!=null && tempSpeciesList.size()>0){
                speciesList = []
                tempSpeciesList.each {species->
                    def ids = taxonomyService.searchTaxonomyIdByTaxonomyName(species)

                    if(ids!=null && ids.size()>0){
                        ids.each {id->
                            if( !idList.contains(id) ){
                                idList.add(id)
                                speciesList.add(species)
                            }
                        }
                    }
                }
            }
            gLogger.info "Species Count :: ${speciesList?.size()}"
        }
        return speciesList
    }

    /**
     * get
     * @param divisionIds
     * @param params
     * @return
     */
    def getSxTaxonomyByDivisionIds(def divisionIds,Map params = [:]){
        //println "params :: ${params}"

        def speciesVOList = null

        if(divisionIds!=null){
            def uniqueSxSpeciesIds

            if(params?.uniqueSxSpeciesIds!=null){
                uniqueSxSpeciesIds = params?.uniqueSxSpeciesIds
            }else{
                uniqueSxSpeciesIds = getUniqueSxSpeciesNCBIIds()
            }

            def taxonomyList
            if( divisionIds instanceof Collection ){
                taxonomyList = TaxonomyNodes.executeQuery("select distinct tn from taxonomy.TaxonomyNodes tn  where tn.division.id in (:divisionIds) and tn.id in (:uniqueSxSpeciesIds) ",["divisionIds":divisionIds,"uniqueSxSpeciesIds":uniqueSxSpeciesIds])
            }else if( divisionIds instanceof Long ){
                taxonomyList = TaxonomyNodes.executeQuery("select distinct tn from taxonomy.TaxonomyNodes tn  where tn.division.id = :divisionIds and tn.id in (:uniqueSxSpeciesIds) ",["divisionIds":divisionIds,"uniqueSxSpeciesIds":uniqueSxSpeciesIds])
            }

            if(taxonomyList!=null && taxonomyList.size()>0){
                speciesVOList = new ArrayList<SpeciesVO>()
                SpeciesVO speciesVO
                taxonomyList.each {TaxonomyNodes taxNode->
                    speciesVO = getSXSpeciesByNCBISpeciesId(taxNode.id)
                    if(speciesVO!=null){
                        speciesVOList.add(speciesVO)
                    }
                }
            }
        }
        return speciesVOList
    }

    def getUniqueDivisions(){
        Collection<TaxonomyDivisionVO> taxonomyDivisionVOList = null

        def taxIds = getUniqueSxSpeciesNCBIIds()
        //println taxIds

        def divisions = taxonomyService.getUniqueDivisionsByNCBIIds(taxIds)

        TaxonomyDivisionVO taxonomyDivisionVO = null
        if(divisions!=null && divisions.size()>0){
           taxonomyDivisionVOList = new ArrayList<TaxonomyDivisionVO>()
           divisions.each {TaxonomyDivisions taxDivision->
               if(taxDivision!=null){
                   taxonomyDivisionVO = new TaxonomyDivisionVO()
                   taxonomyDivisionVO.divisionId = taxDivision.id
                   taxonomyDivisionVO.divisionCode = taxDivision.divisionCode
                   taxonomyDivisionVO.divisionName = taxDivision.divisionName
                   taxonomyDivisionVO.comments = taxDivision.comments
                   def speciesVOList = getSxTaxonomyByDivisionIds(taxDivision.id,["uniqueSxSpeciesIds":taxIds])
                   if(speciesVOList!=null){
                       speciesVOList.each {SpeciesVO speciesVO->
                        if( taxonomyDivisionVO.speciesName !=null){
                             if(taxonomyDivisionVO.speciesName.toString().trim().length()>0){
                                taxonomyDivisionVO.speciesName += "; ${speciesVO.scientificName}"
                             }else{
                                 taxonomyDivisionVO.speciesName = "${speciesVO.scientificName}"
                             }
                        }else{
                            taxonomyDivisionVO.speciesName = "${speciesVO.scientificName}"
                        }

                        if( taxonomyDivisionVO.experimentCount != null ){
                            taxonomyDivisionVO.experimentCount += speciesVO.experimentCount
                            taxonomyDivisionVO.classesCount += speciesVO.classesCount
                            taxonomyDivisionVO.samplesCount += speciesVO.samplesCount
                        }else{
                            taxonomyDivisionVO.experimentCount = speciesVO.experimentCount
                            taxonomyDivisionVO.classesCount = speciesVO.classesCount
                            taxonomyDivisionVO.samplesCount = speciesVO.samplesCount
                        }

                       }
                   }
               }
               gLogger.info "taxonomyDivisionVO :: ${taxonomyDivisionVO}"
               taxonomyDivisionVOList.add(taxonomyDivisionVO)
           }
        }
        return taxonomyDivisionVOList?.sort {it.samplesCount}.reverse()
    }

}
